package com.aiwu;

import android.Manifest;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Process;
import android.text.TextUtils;

import com.aiwu.bean.InitDataBean;
import com.aiwu.library.AiwuSimulator;
import com.aiwu.library.EntryAbsActivity;
import com.aiwu.library.netWork.BaseBean;
import com.aiwu.library.util.DialogUtil;
import com.aiwu.library.util.IOUtil;
import com.aiwu.library.util.LogUtil;
import com.aiwu.library.util.ToastUtil;
import com.aiwu.memory.MemoryManager;
import com.alibaba.fastjson.JSON;

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.citra.citra_emu.CitraApplication;
import org.citra.citra_emu.NativeLibrary;
import org.citra.citra_emu.R;
import org.citra.citra_emu.activities.EmulationActivity;
import org.citra.citra_emu.model.GameDatabase;
import org.citra.citra_emu.utils.DirectoryInitialization;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

import rx.Completable;
import rx.Single;
import rx.SingleEmitter;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.schedulers.Schedulers;


public class EntryActivity extends EntryAbsActivity {
    private final static String TAG = EntryActivity.class.getName();
    private static final String MARKET_GAME_LIST_URI = "25scheme://com.aiwu.market/splash";
    private static final String MARKET_EXTRA_TYPE = "extra_type";
    private static final int TYPE_EMU_GAME_LIST = 7;
    private String gamePath;
    private String gameTitle;


    @Override
    public String[] getPermissions() {
        return new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};
    }

    @Override
    public boolean desktopLaunch() {
        //桌面启动就跳转到游戏宝盒
        try {
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(MARKET_GAME_LIST_URI))
                    .putExtra(MARKET_EXTRA_TYPE, TYPE_EMU_GAME_LIST)
                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        } catch (Exception e) {
            e.printStackTrace();
            try {
                Intent intent = new Intent(Intent.ACTION_VIEW)
                        .setClassName("com.aiwu.market", "com.aiwu.market.ui.activity.SplashActivity")
                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
            } catch (Exception e1) {
                e1.printStackTrace();
                ToastUtil.toast(R.string.jump_market_error);
            }
        }
        finish();
        return true;
    }

    @Override
    public void startGame(String path, boolean isIntentUri) {
        DirectoryInitialization.start(this);
        //如果是文件直接跳转就不请求金手指
        if (isIntentUri) {
            checkInstallStatus(path);
        } else {
            //获取游戏的gameId 跟本地数据库的gameId对应
            requestInitData(new InitCallback() {
                @Override
                public void onSuccess(com.lzy.okgo.model.Response<BaseBean<InitDataBean>> response) {
                    BaseBean<InitDataBean> bean = response.body();
                    if (bean != null && bean.getCode() == 0) {
                        InitDataBean initBean = bean.getData();
                        if (initBean != null) {
                            //写金手指文件
                            final String cheatFilePath = AiwuSimulator.getCheatListener().getCheatFilePath(initBean);
                            AiwuSimulator.getCheatListener().write2CheatFile(cheatFilePath, initBean);
                            //写金手指json文件
                            final String cheatJsonFilePath = AiwuSimulator.getCheatListener().getCheatJsonFilePath();
                            String cheatJson = JSON.toJSONString(initBean);
                            AiwuSimulator.getCheatListener().write2CheatJsonFile(cheatJsonFilePath, cheatJson);

                            ConfigManager.getInstance().setConfigBean(initBean.getConfig());
                            ConfigManager.getInstance().saveConfig2File(initBean.getConfig());
                            //检查cia
                            String romName = initBean.getRomName();
                            LogUtil.d(TAG, "RomName：" + romName);
                            if (!TextUtils.isEmpty(romName)) {
                                checkInstallStatus(path, romName);
                                return;
                            }
                        }
                    }
                    checkInstallStatus(path);
                }

                @Override
                public void onError(com.lzy.okgo.model.Response<BaseBean<InitDataBean>> response) {
                    checkInstallStatus(path);
                }
            });
        }
    }

    /**
     * 检查安装状态 不带romName
     *
     * @param path
     */
    private void checkInstallStatus(String path) {
        ConfigManager.getInstance().setConfigBean(null);
        String spRomName = PrefsHelper.getInstance().getRomNameById(getMarketAppGameId());
        if (TextUtils.isEmpty(spRomName)) {
            spRomName = PrefsHelper.getInstance().getRomNameByPath(path);
        }
        if (TextUtils.isEmpty(spRomName)) {
            //从文件中取romName
            Single.fromEmitter((Action1<SingleEmitter<String>>) singleEmitter -> {
                String gameId = Util.getGameIdFromFile(path);
                if (TextUtils.isEmpty(gameId)) {
                    singleEmitter.onError(new Exception("没找到游戏ID"));
                } else {
                    singleEmitter.onSuccess(gameId);
                }
            }).subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(romName -> checkInstallStatus(path, romName), throwable -> {
                        throwable.printStackTrace();
                        DialogUtil.showTip(this, "打开游戏出错", "爱吾游戏宝盒下载的游戏：首次打开游戏需要联网,如果已经联网请联系管理员。\n" +
                                "爱吾游戏宝盒导入的游戏：首次不能从桌面快捷打开游戏，如有问题请尝试重新导入。\n" +
                                "文件直接打开游戏：文件可能有误!", "确定", v -> {
                            finish();
                            Process.killProcess(Process.myPid());
                        }, null, null, false);
                    });
        } else {
            checkInstallStatus(path, spRomName);
        }
    }

    /**
     * 检查安装状态 已安装的就直接打开游戏
     *
     * @param path
     * @param id
     */
    private void checkInstallStatus(String path, String id) {
        saveRomName2Sp(path, id);
        CitraApplication.setRomName(id);
        CitraApplication.databaseHelper.getGameFromId(id, true)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(game ->//安装过了
                {
                    gamePath = game.getPath();
                    gameTitle = game.getTitle();
                    startEntryGameTimer();
                }, throwable -> {//没安装过
                    throwable.printStackTrace();
                    File sourceFile = new File(path);
                    if (!sourceFile.exists()) {
                        error("游戏文件不存在,请在爱吾游戏宝盒删除后重新下载");
                        return;
                    }
                    //解压文件
                    unzip(path, id);
                });
    }

    /**
     * 保存RomName的关联到Sp
     *
     * @param path
     * @param romName
     */
    private void saveRomName2Sp(String path, String romName) {
        if (getMarketAppGameId() != 0) {
            PrefsHelper.getInstance().setRomNameWithId(getMarketAppGameId(), romName);
        }
        PrefsHelper.getInstance().setRomNameWithPath(path, romName);
    }

    /**
     * 通过id启动游戏
     *
     * @param id
     */
    private void startGameById(String zipPath, List<String> ciaList, String id) {
        CitraApplication.databaseHelper.getGameFromId(id, false)
                .subscribeOn(Schedulers.io())
                .doOnSuccess(game -> {
                    //删除zip和cia
                    if (getDeleteZip() && canDeleteFile(zipPath)) {
                        new File(zipPath).delete();
                    }
                    //如果是文件直接跳转就不删除cia了
                    if (!isIntentUri()) {
                        for (String p : ciaList) {
                            new File(p).delete();
                        }
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(game ->//安装过了
                {
                    gamePath = game.getPath();
                    gameTitle = game.getTitle();
                    startEntryGameTimer();
                }, throwable -> {//没安装过
                    throwable.printStackTrace();
                    error("错误：rom 未安装");
                });
    }

    /**
     * 解压
     */
    private void unzip(String path, String id) {
        File oldFile = new File(path);
        if (Util.getExternalAvailableSize() < oldFile.length()) {
            error("错误：SD卡储存空间不足,无法解压");
            return;
        }
        Single.fromCallable(() -> {
            try {
                List<String> resultList = new ArrayList<>();
                long zipSize = IOUtil.getZipSize(path);//zip总大小
                long unzipCount = 0;//已解压大小
                long lastProgressTime = 0;//上次刷新进度的时间戳,100毫秒刷新一次
                ZipFile zipFile = new ZipFile(path, "GBK");
                //获取压缩包的所有文件
                Enumeration<ZipEntry> entries = zipFile.getEntries();
                while (entries.hasMoreElements()) {
                    ZipEntry zipEntry = entries.nextElement();
                    if (!zipEntry.isDirectory()) {
                        String name = zipEntry.getName();
                        if (name.endsWith(".txt")) {
                            continue;
                        }
                        //单独处理user.zip解压到citra_emu目录
                        boolean isUserZip = name.equalsIgnoreCase("user.zip");
                        //解压后的文件
                        File unzipFile = new File(oldFile.getParent(), name);
                        //解压到文件
                        unzipFile.createNewFile();
                        InputStream is = new BufferedInputStream(zipFile.getInputStream(zipEntry));
                        FileOutputStream fos = new FileOutputStream(unzipFile);
                        byte[] buffer = new byte[1024];
                        int count = is.read(buffer);
                        while (count != -1) {
                            fos.write(buffer, 0, count);
                            unzipCount += count;
                            if (System.currentTimeMillis() - lastProgressTime >= 100 || unzipCount >= zipSize) {
                                lastProgressTime = System.currentTimeMillis();
                                int progress = (int) (unzipCount * 1f / zipSize * 100);
                                refreshUnzipProgress(progress);
                            }
                            count = is.read(buffer);
                        }
                        is.close();
                        fos.close();
                        if (isUserZip) {
                            IOUtil.unzipFile(unzipFile.getAbsolutePath(), Util.getDefaultDir(), false);
                            unzipFile.delete();
                        } else {
                            resultList.add(unzipFile.getAbsolutePath());
                        }
                    }
                }
                zipFile.close();
                return resultList;
            } catch (IOException e) {
                e.printStackTrace();
                return Collections.singletonList(path);
            }
        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe((Action0) () -> {
                    showLoadingTip("正在解压中,请勿离开此页面…");
                })
                .subscribe(paths -> {
                    //安装rom
                    installRom(path, paths, id);
                }, throwable -> {
                    throwable.printStackTrace();
                    error("错误：解压 zip 失败");
                    closeLoadingTip();
                });
    }

    private void refreshUnzipProgress(int progress) {
        runOnUiThread(() -> {
            showLoadingTip("正在解压中" + progress + "%,请勿离开此页面…");
        });
    }

    /**
     * 安装rom
     *
     * @param path
     * @param id
     */
    private void installRom(String zipPath, List<String> path, String id) {
        List<String> ciaList = new ArrayList<>();
        List<String> cciList = new ArrayList<>();
        for (String p : path) {
            switch (Util.getFileExtension(p).toLowerCase()) {
                case ".cia":
                    ciaList.add(p);
                    break;
                case ".cxi":
                case ".app":
                case ".3ds":
                case ".cci":
                    cciList.add(p);
                    break;
                default:
                    break;
            }
        }
        if (ciaList.isEmpty() && cciList.isEmpty()) {
            //文件有误
            error("错误：游戏文件有误，请在爱吾游戏宝盒重新打开游戏，或者删除游戏后重新下载");
            return;
        }
        long installCIASSize = 0;
        if (!ciaList.isEmpty()) {
            for (String p : ciaList) {
                File file = new File(p);
                installCIASSize += file.length();
            }
            //再加个50MB
            installCIASSize += 50 * 1024 * 1024;
        }
        if (Util.getExternalAvailableSize() < installCIASSize) {
            error("错误：SD卡储存空间不足,无法安装");
            return;
        }
        Completable.fromAction(() -> {
            GameDatabase databaseHelper = CitraApplication.databaseHelper;
            SQLiteDatabase database = CitraApplication.databaseHelper.getWritableDatabase();
            if (!ciaList.isEmpty()) {
                NativeLibrary.InstallCIAS(ciaList.toArray(new String[0]));
            }
            if (!cciList.isEmpty()) {
                for (String cci : cciList) {
                    GameDatabase.attemptToAddGame(database, cci);
                }
            }
            databaseHelper.scanLibrary(database);
        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(subscription -> {
                    showLoadingTip("安装中,请勿离开此页面…");
                })
                .doOnCompleted(this::closeLoadingTip)
                .subscribe(() -> {
                    startGameById(zipPath, ciaList, id);
                }, throwable -> {
                    LogUtil.d(TAG, throwable.getMessage());
                    error("错误：安装 rom 失败");
                });
    }

    private boolean canDeleteFile(String filePath) {
        return Util.getFileExtension(filePath).equalsIgnoreCase(".cia") || Util.getFileExtension(filePath).equalsIgnoreCase(".zip");
    }

    @Override
    public void startGameAct() {
        //重置一些值
        MemoryManager.getInstance().reset();
        //后台配置
        ConfigManager.getInstance().handleConfigBean(CitraApplication.getRomName());
        EmulationActivity.launch(this, gamePath, gameTitle, AiwuSimulator.ROM_PATH);
    }

    @Override
    public void settingGame(String path) {

    }

    @Override
    public void deleteGame(List<String> list) {

    }

    @Override
    public int unzipRomFile(String s) {
        return UNZIP_NO;
    }
}
